package com.thfw.test.utils;

import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.text.TextUtils;


import androidx.core.content.FileProvider;

import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.FileReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;


/**
 *
 * Created by jiangwj on 2015/5/7.
 */
public final class StorageUtil {

    public static final File MEDIA_STORE_DIR = new File(
            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM),
            "scooper"
    );

    public static File getPictureOutputFile() {
        File dir = MEDIA_STORE_DIR;
        if (!dir.exists()) {
            if (!dir.mkdirs()) {
                return null;
            }
        }
        //
        String timestamp = new SimpleDateFormat("yyMMdd_HHmmss").format(new Date());
        return new File(dir, "IMG_" + timestamp + ".jpg");
    }

    public static File getVideoOutputDirFile() {
        File dir = MEDIA_STORE_DIR;
        if (!dir.exists()) {
            dir.mkdirs();
        }
        //
        return dir;
    }

    public static Uri getUriForFile(@NotNull Context context, File file) {
        if (context == null || file == null) {
            throw new NullPointerException();
        }
        Uri uri;
        if (Build.VERSION.SDK_INT >= 24) {
            uri = FileProvider.getUriForFile(context.getApplicationContext(), "com.thfw.test.utils", file);
        } else {
            uri = Uri.fromFile(file);
        }
        return uri;
    }

    public static String getAbsolutePathFromUri(Context context, Uri uri) {
        if (null == uri) {
            return null;
        }
        final String scheme = uri.getScheme();
        String data = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
                && isFileProvider(context, uri)) {
            return getPathFromProviderUri(context, uri);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
                && DocumentsContract.isDocumentUri(context, uri)) {
            if (isExternalStorageDocument(uri)) {   // ExternalStorageProvider
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                if ("primary".equalsIgnoreCase(type)) {
                    return Environment.getExternalStorageDirectory() + File.separator + split[1];
                }

            } else if (isDownloadsDocument(uri)) {  // DownloadsProvider
                final String id = DocumentsContract.getDocumentId(uri);
                final Uri contentUri = ContentUris
                        .withAppendedId(Uri.parse("content://downloads/public_downloads"),
                                Long.valueOf(id));

                return getDataColumn(context, contentUri, null, null);

            } else if (isMediaDocument(uri)) {      // MediaProvider
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                Uri contentUri = null;
                String column = "_id";
                String id = split[1];
                if ("image".equals(type)) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                    column = MediaStore.Images.Media._ID;
                } else if ("video".equals(type)) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                    column = MediaStore.Video.Media._ID;
                } else if ("audio".equals(type)) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                    column = MediaStore.Audio.Media._ID;
                }

                return getDataColumn(context, contentUri,
                        column + " = ?",
                        new String[] { id });
            }

        } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
            data = getDataColumn(context, uri, null, null);
        } else if (ContentResolver.SCHEME_FILE.equals(scheme)) {
            data = uri.getPath();
        } else {
            data = uri.getPath();
        }
        return data;
    }

    /**
     * 获取 Uri 的绝对地址，用于 MediaStore 类型的 Uri，和其他基础文件类型的 ContentProvider
     * @param context context
     * @param uri 查询的 uri
     * @param selection 过滤的条件
     * @param selectionArgs 过滤的参数
     * @return 返回绝对地址
     */
    private static String getDataColumn(Context context, Uri uri, String selection,
                                        String[] selectionArgs) {
        // MediaStore.Images.Media.DATA == MediaStore.Video.Media.DATA == "_data"
        final String[] projection = new String[] { "_data" };
        Cursor cursor = null;
        ContentResolver contentResolver = context.getApplicationContext().getContentResolver();
        try {
            cursor = MediaStore.Images.Media.query(contentResolver, uri, projection, selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                final int columnIndex = cursor.getColumnIndex(projection[0]);
                return columnIndex >= 0 ? cursor.getString(columnIndex) : null;
            }
        } finally {
            FileUtils.closeIO(cursor);
        }
        return null;
    }

    /**
     * 获取 Uri 的绝对地址，用于 FileProvider 类型的 Uri
     * @param context context
     * @param uri 查询的 uri
     * @return 返回绝对地址，获取失败返回空
     */
    private static String getPathFromProviderUri(Context context, Uri uri) {
        PackageInfo packageInfo = null;
        try {
            packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PROVIDERS);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        if (packageInfo == null) {
            return null;
        }
        ProviderInfo[] providers = packageInfo.providers;
        if (providers == null || providers.length == 0) {
            return null;
        }
        for (ProviderInfo providerInfo : providers) {
            if (TextUtils.equals(uri.getAuthority(), providerInfo.authority)
                    && FileProvider.class.getName().equalsIgnoreCase(providerInfo.name)) {
                try {
                    Method getPathStrategy = FileProvider.class.getDeclaredMethod("getPathStrategy", Context.class, String.class);
                    getPathStrategy.setAccessible(true);
                    // 获取 PathStrategy
                    Object invoke = getPathStrategy.invoke(null, context, uri.getAuthority());
                    if (invoke == null) {
                        return null;
                    }
                    String PathStrategyClassName = FileProvider.class.getName() + "$PathStrategy";
                    Class<?> PathStrategy = Class.forName(PathStrategyClassName);
                    Method getFileForUri = PathStrategy.getDeclaredMethod("getFileForUri", Uri.class);
                    getFileForUri.setAccessible(true);
                    Object fileInvoke = getFileForUri.invoke(invoke, uri);
                    if (fileInvoke instanceof File) {
                        return ((File) fileInvoke).getAbsolutePath();
                    }
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     *
     * @param context context
     * @param uri 检查的 Uri
     * @return Uri 的 authority 是否 FileProvider
     */
    private static boolean isFileProvider(Context context, Uri uri) {
        List<PackageInfo> packages = context.getPackageManager().getInstalledPackages(PackageManager.GET_PROVIDERS);
        if (packages != null && packages.size() > 0) {
            for (PackageInfo packageInfo : packages) {
                ProviderInfo[] providers = packageInfo.providers;
                if (providers != null && providers.length > 0) {
                    for (ProviderInfo providerInfo : providers) {
                        if (TextUtils.equals(uri.getAuthority(), providerInfo.authority)
                                && FileReader.class.getName().equalsIgnoreCase(providerInfo.name)) {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }

    /**
     * @param uri 检查的 Uri
     * @return Uri 的 authority 是否 ExternalStorageProvider
     */
    private static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri.getAuthority());
    }

    /**
     * @param uri 检查的 Uri
     * @return Uri 的 authority 是否 DownloadsProvider
     */
    private static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
    }

    /**
     * @param uri 检查的 Uri
     * @return Uri 的 authority 是否 MediaProvider
     */
    private static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getAuthority());
    }
}
